Skip to content

fix(autofix): Remove unconfigured projects gate and remove code mapping repos fallback#113077

Open
srest2021 wants to merge 12 commits intomasterfrom
srest2021/fix-empty-repos-fallback
Open

fix(autofix): Remove unconfigured projects gate and remove code mapping repos fallback#113077
srest2021 wants to merge 12 commits intomasterfrom
srest2021/fix-empty-repos-fallback

Conversation

@srest2021
Copy link
Copy Markdown
Member

@srest2021 srest2021 commented Apr 15, 2026

The Sentry DB project preference read helpers had a has_configured_options gate that returned None for projects with no repos and no non-default options. This was problematic because the gate could treat a pref with no repos and explicitly set default options as unconfigured and return None, and _resolve_project_preference would then create a new pref using code mapping repos. We also don't want to fall back to code mappings or create new prefs with them, since we'd be adding to users' bills.

In this PR:

  • read_preference_from_sentry_db and bulk_read_preferences_from_sentry_db now always return a SeerProjectPreference (never None). Clean up callsites that had redundant if preference: guards on the Sentry DB read path.
  • Simplify _resolve_project_preference to return the existing preference as-is (even with empty repos) and remove the code mapping fallback in trigger_autofix. When no preference exists (Seer API returned None), creates a new one with empty repos and org defaults.

The night shift cron job is unaffected — it already filters on pref.repositories and pref.autofix_automation_tuning != OFF, so receiving a default preference instead of None doesn't change which projects are selected.

read_preference_from_sentry_db now always returns a SeerProjectPreference
instead of None, removing the has_configured_options gate that could
incorrectly treat mechanically-written default options as "configured".

_resolve_project_preference now checks preference.repositories instead
of just truthiness — when repos are empty it falls through to the code
mapping fallback while preserving the user's existing stopping point
and handoff settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Apr 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

Backend Test Failures

Failures on a29e676 in this run:

tests/sentry/seer/autofix/test_autofix_utils.py::TestBulkReadPreferencesFromSentryDb::test_autofix_automation_tuning_populatedlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/autofix/test_autofix_utils.py:1529: in test_autofix_automation_tuning_populated
    assert result[self.project2.id] is None
E   AssertionError: assert SeerProjectPreference(organization_id=4557973359689744, project_id=4557973359689745, repositories=[], automated_run_st..._point='code_changes', automation_handoff=None, autofix_automation_tuning=<AutofixAutomationTuningSettings.OFF: 'off'>) is None
tests/sentry/seer/autofix/test_autofix_utils.py::TestBulkReadPreferencesFromSentryDb::test_unconfigured_project_returns_nonelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/autofix/test_autofix_utils.py:1475: in test_unconfigured_project_returns_none
    assert result == {self.project1.id: None}
E   AssertionError: assert {455797335995....OFF: 'off'>)} == {4557973359951888: None}
E     
E     Differing items:
E     {4557973359951888: SeerProjectPreference(organization_id=4557973359951888, project_id=4557973359951888, repositories=[...point='code_changes', automation_handoff=None, autofix_automation_tuning=<AutofixAutomationTuningSettings.OFF: 'off'>)} != {4557973359951888: None}
E     
E     Full diff:
E       {
E     -     4557973359951888: None,
E     +     4557973359951888: SeerProjectPreference(organization_id=4557973359951888, project_id=4557973359951888, repositories=[], automated_run_stopping_point='code_changes', automation_handoff=None, autofix_automation_tuning=<AutofixAutomationTuningSettings.OFF: 'off'>),
E       }
tests/sentry/seer/autofix/test_autofix.py::TestResolveProjectPreference::test_returns_preference_with_empty_reposlog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/autofix/test_autofix.py:1235: in test_returns_preference_with_empty_repos
    assert len(result.repositories) == 0
E   AssertionError: assert 1 == 0
E    +  where 1 = len([SeerRepoDefinition(repository_id=None, organization_id=None, integration_id=None, provider='integrations:github', own...', is_private=None, branch_name=None, branch_overrides=[], instructions=None, base_commit_sha=None, provider_raw=None)])
E    +    where [SeerRepoDefinition(repository_id=None, organization_id=None, integration_id=None, provider='integrations:github', own...', is_private=None, branch_name=None, branch_overrides=[], instructions=None, base_commit_sha=None, provider_raw=None)] = SeerProjectPreference(organization_id=4557973359820816, project_id=4557973359820816, repositories=[SeerRepoDefinition(...ng_point='root_cause', automation_handoff=None, autofix_automation_tuning=<AutofixAutomationTuningSettings.OFF: 'off'>).repositories
tests/sentry/seer/autofix/test_autofix_utils.py::TestReadPreferenceFromSentryDb::test_unconfigured_project_returns_nonelog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/autofix/test_autofix_utils.py:1273: in test_unconfigured_project_returns_none
    assert result is None
E   AssertionError: assert SeerProjectPreference(organization_id=4557973359886368, project_id=4557973359886368, repositories=[], automated_run_st..._point='code_changes', automation_handoff=None, autofix_automation_tuning=<AutofixAutomationTuningSettings.OFF: 'off'>) is None

if pref:
repo_definitions = pref.repositories
if pref.automation_handoff:
auto_create_pr = pref.automation_handoff.auto_create_pr
Copy link
Copy Markdown
Member Author

@srest2021 srest2021 Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renaming stuff is due to mypy. read_preference_from_sentry_db guarantees SeerProjectPreference but get_project_seer_preferences can return None. I'll just rename the Seer API call result since it'll get removed soon.

underlying read path (Sentry DB or Seer API)."""
if features.has("organizations:seer-project-settings-read-from-sentry", organization):
return bulk_read_preferences_from_sentry_db(organization.id, project_ids)
return bulk_read_preferences_from_sentry_db(organization.id, project_ids) # type: ignore[return-value]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again mypy. Return type here is dict[int, SeerProjectPreference] so I think it's ok to override mypy

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@srest2021 srest2021 marked this pull request as ready for review April 15, 2026 19:45
@srest2021 srest2021 requested a review from a team as a code owner April 15, 2026 19:45
Comment thread src/sentry/seer/autofix/utils.py
@srest2021 srest2021 marked this pull request as draft April 15, 2026 20:14
@srest2021 srest2021 marked this pull request as ready for review April 15, 2026 22:44
@srest2021 srest2021 changed the title fix(autofix): Fall back to code mappings when preference has empty repos fix(autofix): Remove unconfigured projects gate and remove code mapping repos fallback Apr 15, 2026
Comment thread src/sentry/seer/endpoints/seer_rpc.py
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 15, 2026

Backend Test Failures

Failures on 1f195c1 in this run:

tests/sentry/seer/endpoints/test_group_ai_autofix.py::GroupAutofixEndpointTest::test_ai_autofix_post_without_event_idlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/endpoints/test_group_ai_autofix.py:537: in test_ai_autofix_post_without_event_id
    assert any(
E   assert False
E    +  where False = any(<generator object GroupAutofixEndpointTest.test_ai_autofix_post_without_event_id.<locals>.<genexpr> at 0x7f789c955120>)
tests/sentry/seer/endpoints/test_group_ai_autofix.py::GroupAutofixEndpointTest::test_ai_autofix_post_endpointlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/endpoints/test_group_ai_autofix.py:379: in test_ai_autofix_post_endpoint
    assert any(
E   assert False
E    +  where False = any(<generator object GroupAutofixEndpointTest.test_ai_autofix_post_endpoint.<locals>.<genexpr> at 0x7fd310bfa6b0>)
tests/sentry/seer/endpoints/test_group_ai_autofix.py::GroupAutofixEndpointTest::test_ai_autofix_post_without_event_id_no_recommended_eventlog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/endpoints/test_group_ai_autofix.py:624: in test_ai_autofix_post_without_event_id_no_recommended_event
    assert any(
E   assert False
E    +  where False = any(<generator object GroupAutofixEndpointTest.test_ai_autofix_post_without_event_id_no_recommended_event.<locals>.<genexpr> at 0x7fa83ae145e0>)

Mock _resolve_project_preference to return a SeerProjectPreference
with repos instead of None, since trigger_autofix no longer falls
back to code mapping repos.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Backend Test Failures

Failures on 45b5fe1 in this run:

tests/sentry/seer/endpoints/test_seer_rpc.py::TestSeerRpcMethods::test_get_project_preferences_returns_none_when_no_preferencelog
[gw0] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
tests/sentry/seer/endpoints/test_seer_rpc.py:1554: in test_get_project_preferences_returns_none_when_no_preference
    result = get_project_preferences(
src/sentry/seer/endpoints/seer_rpc.py:891: in get_project_preferences
    return read_preference_from_sentry_db(project).dict()
E   AttributeError: 'NoneType' object has no attribute 'dict'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants